﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Documents;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;

// The Templated Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234235

namespace TouchPoint.ShapeEngine.Shape
{
    using Windows.UI.Input.Inking;
    using System.Text.RegularExpressions;


    //---------------------------------------------------------------------------------------------------
    //  RenderFragment是必须是VisualTree的一个元素,
    //---------------------------------------------------------------------------------------------------
    public sealed class RenderFragment : Control
    {
        public RenderFragment()
        {
            this.DefaultStyleKey = typeof(RenderFragment);
        }


        //---------------------------------------------------------------------------------------------------
        //  原始输入数据,该属性值由用户指定,数据类型为三种 Stroke|String|Byte[],获得该类型的情形分别有:
        //  Stroke类型:
        //  1) 用户在InkCanvas中绘图
        //  Byte[]类型:
        //  1) 用户插入了一段音频数据(从磁盘上加载|从网络上加载|从声音输入设备中获取)
        //  2) 用户插入了一张图片(从磁盘中加载)
        //  String类型:
        //  1) 用户使用输入设备直接输入的文字
        //  2) 用户使用光学识别服务识别的文字
        //  3) 用户在InkCanvas中绘制的Stroke转换而成的文字
        //  4) 用户使用VoiceRecognizer识别出来的文字
        //
        //  注意:
        //  对于图片|音频|视频等对机器资源消耗较大的资源,我们一般交由系统托管,但是在需要对资源修改的场景下我们将会放弃系统托管资源
        //  的优势,转而自行托管资源内容的内存管理
        //---------------------------------------------------------------------------------------------------

        /// <summary>
        /// 设置或获取当前渲染片元的原始输入数据
        /// </summary>
        public object RawInputData {
            get { return (object)GetValue(RawInputDataProperty); }
            set { SetValue(RawInputDataProperty, value); }
        }
        public static readonly DependencyProperty RawInputDataProperty =
            DependencyProperty.Register("RawInputData", typeof(object),
                typeof(RenderFragment), new PropertyMetadata(null));


        //---------------------------------------------------------------------------------------------------
        //  RawInputDataType属性会在设置RawInputData属性值变化的时候更改，也可以自行指定原始输入数据的类型，根据原始输入数据
        //  的类型Generator会相应的改变Content的值。
        //
        //注意:  
        //    当RawInputDataType属性值变化的时候会引起重绘(Re-Rendering)行为
        //注意:
        //    RawInputDataType属性值是第二顺序
        //    RawInputData -> (Assert InputDataType) -> RawInputDataType -> (Generator Generated XAML) -> Rendering
        //
        //---------------------------------------------------------------------------------------------------

        /// <summary>
        /// 获取或设置当前渲染片元的原始输入数据类型
        /// </summary>
        public RenderType RawInputDataType {
            get { return (RenderType)GetValue(RawInputDataTypeProperty); }
            set { SetValue(RawInputDataTypeProperty, value); }
        }
        public static readonly DependencyProperty RawInputDataTypeProperty 
            = DependencyProperty.Register("RawInputDataType",
                typeof(RenderType), 
                typeof(RenderFragment),
                new PropertyMetadata(default(RenderType)));



        //-----------------------------------------------------------------------------------------------------------------------
        //  提示：Content属性会根据RawInputDataType的类型由Generator自动生成对应样式，这里需要尽可能的避免手动指定输出内容。
        //-----------------------------------------------------------------------------------------------------------------------

        /// <summary>
        /// 设置或获取当前渲染片元最终生成的内容
        /// </summary>
        public object Content {
            get { return (object)GetValue(ContentProperty); }
            set { SetValue(ContentProperty, value); }
        }
        public static readonly DependencyProperty ContentProperty 
            = DependencyProperty.Register("Content", 
                typeof(object),
                typeof(RenderFragment),
                new PropertyMetadata(null));


        //---------------------------------------------------------------------------------------------------
        //  唯一识别符用于标识或者引用当前片元,理论而言可以支持2^31个元素,一般只会使用到65536甚至更少的元素
        //---------------------------------------------------------------------------------------------------
        /// <summary>
        /// 当前片元的唯一识别符
        /// </summary>
        public int ElementId {
            get { return (int)GetValue(ElementIdProperty); }
            set { SetValue(ElementIdProperty, value); }
        }
        public static readonly DependencyProperty ElementIdProperty
            = DependencyProperty.Register("ElementId", 
                typeof(int),
                typeof(RenderFragment), 
                new PropertyMetadata(0));


        //---------------------------------------------------------------------------------------------------
        //  ContentGenerator
        //---------------------------------------------------------------------------------------------------
        /// <summary>
        /// ContentGenerator
        /// </summary>
        internal class ContentGenreator
        {
            RenderFragment _element;
            public ContentGenreator(RenderFragment render)
            {
                _element = render;
            }
            //---------------------------------------------------------------------------------------------------
            //  识别HttpScheme|HTTPSScheme的正则表达式  
            //---------------------------------------------------------------------------------------------------
            private const string Http = @"(http|https)://([\w./?#=&%_-]+){0,4}";
            public bool IsHttpLinkSource(object content)
            {
                if(content is string msg)
                {
                    return Regex.IsMatch(msg, Http);
                }
                return false;
            }

            public bool IsBinarySource(object content)
            {
                return content is Byte[];
            }

            public bool IsInkStroke(object content)
            {
                return content is InkStroke;
            }

            public void GenerateContent(object input)
            {

            }
        }
    }
}
